﻿using GameFramework;
using GameFramework.DataTable;
using GameFramework.Resource;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using UnityEngine;
using UnityGameFramework.Runtime;

namespace ProjectMG
{
    public static class DataTableExtension
    {
        private const string DataRowClassPrefixName = "ProjectMG.DR";
        internal static readonly char[] DataSplitSeparators = new char[] { '\t' };
        internal static readonly char[] DataTrimSeparators = new char[] { '\"' };

        private static readonly string[] DataTableNameInTypeSplit = new string[] { "__" };
        private static readonly Dictionary<string, bool> s_DataTableLoadedFlags = new Dictionary<string, bool>();

        public static bool IsAllDataTablesLoaded(this DataTableComponent dataTableComponent)
        {
            if (GameEntry.BuiltinData.UseDataTableBytes)
            {
                // 使用二进制数据表不需要预加载资源了
                return true;
            }

            if (s_DataTableLoadedFlags.Count <= 0)
            {
                return false;
            }

            foreach (KeyValuePair<string, bool> dataTableLoadedFlag in s_DataTableLoadedFlags)
            {
                if (!dataTableLoadedFlag.Value)
                {
                    return false;
                }
            }

            return true;
        }

        public static void SetDataTableLoadedFlag(this DataTableComponent dataTableComponent, string dataTableName)
        {
            if (s_DataTableLoadedFlags.ContainsKey(dataTableName))
            {
                s_DataTableLoadedFlags[dataTableName] = true;
            }
            else
            {
                Log.Warning("Not load data table '{0}' yet.", dataTableName);
            }
        }

        public static void LoadDataTables(this DataTableComponent dataTableComponent)
        {
            s_DataTableLoadedFlags.Clear();
            GameEntry.Resource.LoadBinary("Assets/GameMain/DataTables/DataTableList.txt", new LoadBinaryCallbacks(LoadDataTableListSuccessCallback, LoadDataTableListFailureCallback));
        }

        private static void LoadDataTableListSuccessCallback(string binaryAssetName, byte[] binaryBytes, float duration, object userData)
        {
            string[] LineSplit = new string[] { "\r\n", "\r", "\n" };
            string[] dataTableNames = Utility.Converter.GetString(binaryBytes).Split(LineSplit, StringSplitOptions.None);
            foreach (string dataTableName in dataTableNames)
            {
                LoadDataTable(dataTableName);
            }
        }

        private static void LoadDataTableListFailureCallback(string binaryAssetName, LoadResourceStatus status, string errorMessage, object userData)
        {
            Log.Error("Load data table list asset failure, status is '{0}', error message is '{1}'.", status.ToString(), errorMessage);
        }

        private static void LoadDataTable(string dataTableName)
        {
            if (string.IsNullOrEmpty(dataTableName))
            {
                Log.Error("Data table name is invalid.");
                return;
            }

            string[] splitNames = dataTableName.Split(DataTableNameInTypeSplit, StringSplitOptions.None);
            if (splitNames.Length > 2)
            {
                Log.Error("Data table name is invalid.");
                return;
            }

            string dataRowClassName = DataRowClassPrefixName + splitNames[0];
            Type dataRowType = Type.GetType(dataRowClassName);
            if (dataRowType == null)
            {
                Log.Error("Can not get data row type with class name '{0}'.", dataRowClassName);
                return;
            }

            string name = splitNames.Length > 1 ? splitNames[1] : null;
            string assetName = AssetUtility.GetDataTableAsset(dataTableName);
            s_DataTableLoadedFlags.Add(assetName, false);
            DataTableBase dataTable = GameEntry.DataTable.CreateDataTable(dataRowType, name);
            dataTable.ReadData(assetName, Constant.AssetPriority.DataTableAsset, GameEntry.BuiltinData.UseDataTableBytes);
        }

        public static Color32 ParseColor32(string value)
        {
            string[] splitValue = value.Split(',');
            return new Color32(byte.Parse(splitValue[0]), byte.Parse(splitValue[1]), byte.Parse(splitValue[2]), byte.Parse(splitValue[3]));
        }

        public static Color ParseColor(string value)
        {
            string[] splitValue = value.Split(',');
            return new Color(float.Parse(splitValue[0]), float.Parse(splitValue[1]), float.Parse(splitValue[2]), float.Parse(splitValue[3]));
        }

        public static Quaternion ParseQuaternion(string value)
        {
            string[] splitValue = value.Split(',');
            return new Quaternion(float.Parse(splitValue[0]), float.Parse(splitValue[1]), float.Parse(splitValue[2]), float.Parse(splitValue[3]));
        }

        public static Rect ParseRect(string value)
        {
            string[] splitValue = value.Split(',');
            return new Rect(float.Parse(splitValue[0]), float.Parse(splitValue[1]), float.Parse(splitValue[2]), float.Parse(splitValue[3]));
        }

        public static Vector2 ParseVector2(string value)
        {
            string[] splitValue = value.Split(',');
            return new Vector2(float.Parse(splitValue[0]), float.Parse(splitValue[1]));
        }

        public static Vector3 ParseVector3(string value)
        {
            string[] splitValue = value.Split(',');
            return new Vector3(float.Parse(splitValue[0]), float.Parse(splitValue[1]), float.Parse(splitValue[2]));
        }

        public static Vector4 ParseVector4(string value)
        {
            string[] splitValue = value.Split(',');
            return new Vector4(float.Parse(splitValue[0]), float.Parse(splitValue[1]), float.Parse(splitValue[2]), float.Parse(splitValue[3]));
        }

        public static int[] ParseIntArray(string value)
        {
            string[] splitValue = value.Split(';');
            int[] arr = new int[splitValue.Length];
            for (int i = 0; i < splitValue.Length; i++)
            {
                arr[i] = int.Parse(splitValue[i]);
            }
            return arr;
        }

        public static T[] ParseArray<T>(string value)
        {
            string[] splitValue = value.Split('|');
            if (splitValue.Length <= 1)
            {
                splitValue = value.Split(',');
            }
            T[] arr = new T[splitValue.Length];
            for (int i = 0; i < splitValue.Length; i++)
            {
                arr[i] = ParseCustomType<T>(splitValue[i]);
            }
            return arr;
        }

        public static List<T> ParseList<T>(string value)
        {
            string[] splitValue = value.Split('|');
            if (splitValue.Length <= 1)
            {
                splitValue = value.Split(',');
            }
            List<T> list = new List<T>();
            for (int i = 0; i < splitValue.Length; i++)
            {
                list.Add(ParseCustomType<T>(splitValue[i]));
            }
            return list;
        }

        public static Dictionary<TKey, TValue> ParseDictionary<TKey, TValue>(string strValue)
        {
            Dictionary<TKey, TValue> dictionary = new Dictionary<TKey, TValue>();
            string[] splitValue = strValue.Split('|');
            for (int i = 0; i < splitValue.Length; i++)
            {
                string[] parts = splitValue[i].Split('#');
                if (parts.Length == 2)
                {
                    TKey key = ParseCustomType<TKey>(parts[0].Substring(1));
                    TValue value = ParseCustomType<TValue>(parts[1].Substring(0, parts[1].Length - 1));
                    dictionary.Add(key, value);
                }
            }
            return dictionary;
        }

        private static T ParseCustomType<T>(string strValue)
        {
            Type type = typeof(T);
            if (type == typeof(string))
            {
                return (T)(object)strValue;
            }
            else if (type == typeof(bool))
            {
                return (T)(object)bool.Parse(strValue);
            }
            else if (type == typeof(byte))
            {
                return (T)(object)byte.Parse(strValue);
            }
            else if (type == typeof(sbyte))
            {
                return (T)(object)sbyte.Parse(strValue);
            }
            else if (type == typeof(char))
            {
                return (T)(object)char.Parse(strValue);
            }
            else if (type == typeof(decimal))
            {
                return (T)(object)decimal.Parse(strValue);
            }
            else if (type == typeof(DateTime))
            {
                return (T)(object)DateTime.Parse(strValue);
            }
            else if (type == typeof(int))
            {
                return (T)(object)int.Parse(strValue);
            }
            else if (type == typeof(short))
            {
                return (T)(object)short.Parse(strValue);
            }
            else if (type == typeof(long))
            {
                return (T)(object)long.Parse(strValue);
            }
            else if (type == typeof(uint))
            {
                return (T)(object)uint.Parse(strValue);
            }
            else if (type == typeof(ushort))
            {
                return (T)(object)ushort.Parse(strValue);
            }
            else if (type == typeof(ulong))
            {
                return (T)(object)ulong.Parse(strValue);
            }
            else if (type == typeof(float))
            {
                return (T)(object)float.Parse(strValue);
            }
            else if (type == typeof(double))
            {
                return (T)(object)double.Parse(strValue);
            }
            else if (type == typeof(Color))
            {
                return (T)(object)ParseColor(strValue);
            }
            else if (type == typeof(Color32))
            {
                return (T)(object)ParseColor32(strValue);
            }
            else if (type == typeof(Rect))
            {
                return (T)(object)ParseRect(strValue);
            }
            else if (type == typeof(Vector2))
            {
                return (T)(object)ParseVector2(strValue);
            }
            else if (type == typeof(Vector3))
            {
                return (T)(object)ParseVector3(strValue);
            }
            else if (type == typeof(Vector4))
            {
                return (T)(object)ParseVector4(strValue);
            }
            else if (type == typeof(Quaternion))
            {
                return (T)(object)ParseQuaternion(strValue);
            }
            else
            {
                Log.Error("data type that does not exist：{0}!", type.ToString());
            }
            return default(T);
        }
    }
}
